home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
doom
/
chasecam.zip
/
QC106.ZIP
/
hook.qc
< prev
next >
Wrap
Text File
|
1997-04-20
|
12KB
|
419 lines
//====================================================================
//
// SWINGING GRAPPLING HOOK by: Perecli Manole AKA Bort
//
//====================================================================
// Aside from this new file, the following are the modifications
// done to id's original source files:
//--------------------------------------------------------------------
// File: Progs.src
// Location: before the "weapons.qc" line
// Added: hook.qc
//--------------------------------------------------------------------
// File: Client.qc
// Procedure: PlayerPreThink
// Location: after line "WaterMove ();"
// Added: CheckGrapHook ();
//--------------------------------------------------------------------
// File: World.qc
// Procedure: worldspawn
// Location: after line "precache_model ("progs/s_spike.mdl");"
// Added: precache_model ("progs/hook.mdl");
// precache_model ("progs/bit.mdl");
//--------------------------------------------------------------------
// File: Weapons.qc
// Procedure: W_Precache
// Location: end of procedure
// Added: precache_sound ("shambler/smack.wav");
// precache_sound ("blob/land1.wav");
// precache_sound ("hook/chain1.wav");
// precache_sound ("hook/chain2.wav");
// precache_sound ("hook/retract.wav");
//--------------------------------------------------------------------
// File: Defs.qc
// Declaration group: player only fields
// Location: after line ".float pain_finished;"
// Added: .float hook;
//--------------------------------------------------------------------
void(vector org, vector vel, float damage) SpawnBlood; // prototype
float () crandom; // prototype
float HOOK_OUT = 1; // bit flag on if hook has been launched
float HOOK_ON = 2; // bit flag on if hook command is active
float SHRINK_ON = 4; // bit flag on if shrink chain is active
float GROW_ON = 8; // bit flag on if grow chain is active
// Rob; used to stop auto shrink if action key released prior to hit
float HOOK_SG_STOP = 16;
// impulse constants
float I_HOOK = 98;
float I_GROW = 97;
float I_SHRINK = 96;
float I_STOP = 95;
float MIN_CHAIN_LEN = 40; // minimum chain length
float MAX_CHAIN_LEN = 1000; // maximum chain length
float GROW_SHRINK_RATE = 40; // speed of chain growth/shrink
//--------------------------------------------------------------------
// Vector dot product function
//--------------------------------------------------------------------
float (vector from, vector onto) Dot =
{
return from_x * onto_x + from_y * onto_y + from_z * onto_z;
};
//--------------------------------------------------------------------
// Removes hook and detaches player
//--------------------------------------------------------------------
void () DropHook =
{
local entity linkptr;
local entity nextptr;
// remove all hook flags
self.owner.hook = 0;
// removes chain
linkptr = self.goalentity;
while (linkptr != world)
{
nextptr = linkptr.goalentity;
remove (linkptr);
linkptr = nextptr;
}
sound (self.owner, CHAN_AUTO, "hook/retract.wav", 1, ATTN_NORM);
// removes hook
remove (self);
};
//--------------------------------------------------------------------
// Updated calculation of link positions
//--------------------------------------------------------------------
void () LinkPos =
{
setorigin (self, self.owner.origin + ((self.enemy.origin + '0 0 16') - self.owner.origin) * self.weapon);
self.nextthink = time + 0.01;
};
//--------------------------------------------------------------------
// Creates chain
//--------------------------------------------------------------------
entity (entity head, entity tail, float num) CreateChain =
{
local entity link, prevlink;
local float linknum;
linknum = num;
num = num + 1;
prevlink = world;
while (linknum > 0)
{
link = spawn();
link.goalentity = prevlink;
prevlink = link;
link.owner = head;
link.enemy = tail;
link.weapon = linknum / num;
link.movetype = MOVETYPE_NOCLIP;
link.solid = SOLID_NOT;
link.angles_z = 51 * linknum;
link.angles_y = 41 * linknum;
link.angles_x = 31 * linknum;
link.avelocity = '310 410 510';
setmodel (link, "progs/bit.mdl");
setsize (link, '0 0 0', '0 0 0');
setorigin (link, head.origin + ((tail.origin + '0 0 16') - head.origin) * link.weapon);
link.nextthink = time + 0.01;
link.think = LinkPos;
linknum = linknum - 1;
}
return link;
};
//--------------------------------------------------------------------
// Hook behavior function
//--------------------------------------------------------------------
void () HookBehavior =
{
local vector spray; // for blood
local vector chainvec; // chain vector
local vector velpart; // player velocity moving away from hook
local float chainlength; // length of extended chain
local float f1; // antigravity force
local float i1, i2; // intermediate values
self.nextthink = time + 0.1;
// decide when to disconnect hook
if ( !(self.owner.hook & HOOK_ON) ||
(self.owner.teleport_time > time) || // if player goes through teleport
self.owner.deadflag || // if player dies
(self.enemy.solid == SOLID_NOT) ) // if target dies
{
DropHook();
return;
}
// give some damage to entities that take damage
if (self.enemy.takedamage)
T_Damage (self.enemy, self, self.owner, 3);
// when hook hits player add blood and sounds
if (self.enemy.solid == SOLID_SLIDEBOX)
{
sound (self, CHAN_AUTO, "blob/land1.wav", 0.8, ATTN_NORM);
spray_x = 100 * crandom();
spray_y = 100 * crandom();
spray_z = 100 * crandom() + 50;
SpawnBlood (self.origin, spray, 20);
setorigin (self, self.enemy.origin + self.enemy.mins + self.enemy.size * 0.5);
}
self.velocity = self.enemy.velocity;
// chain physics
chainvec = self.origin - (self.owner.origin + '0 0 16');
chainlength = vlen (chainvec);
// Rob; changed shrink and grow structures
// trivial things to make the formula work bug-free with QC
// (You find this in a book, Bort? Otherwise you're a freagin
// math wizard :-)
if ( (self.owner.hook & GROW_ON) )
{
if ( (self.owner.flags & FL_ONGROUND) )
self.armorvalue = chainlength;
else
{
self.armorvalue = self.armorvalue + GROW_SHRINK_RATE;
sound (self.owner, CHAN_AUTO,
"hook/chain1.wav", 0.8, ATTN_NORM);
}
if ( self.armorvalue > MAX_CHAIN_LEN )
self.armorvalue = MAX_CHAIN_LEN;
}
// shrink the length of the chain
if ( (self.owner.hook & SHRINK_ON) )
{
// fixes not raising when directly under the hook
self.owner.flags = self.owner.flags -
(self.owner.flags & FL_ONGROUND);
self.armorvalue = self.armorvalue - GROW_SHRINK_RATE;
if (self.armorvalue < MIN_CHAIN_LEN)
self.armorvalue = MIN_CHAIN_LEN;
else
sound (self.owner, CHAN_AUTO,
"hook/chain2.wav", 0.8, ATTN_NORM);
}
// if player's location is beyond the chain's reach
if (chainlength > self.armorvalue)
{
// derives force towards hook
f1 = (chainlength - self.armorvalue) * 3;
// determine player's velocity part moving away from hook
i1 = Dot(self.owner.velocity,chainvec);
i2 = Dot(chainvec,chainvec);
velpart = chainvec * (i1 / i2);
// get magnitude(tug on chain) of velpart
i1 = vlen (velpart);
// if hard tug on the chain add a bounce
if (i1 > 450) velpart = velpart * 1.35;
// apply chain restrainment
self.owner.velocity = self.owner.velocity - velpart;
// if harder tug on chain, then inflict pain
if (i1 > 900)
{
T_Damage (self.owner, world, world, 5);
sound (self.owner, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM);
}
}
else
f1 = 0;
// applys forces to players velocity
self.owner.velocity = self.owner.velocity + normalize(chainvec) * f1;
};
//--------------------------------------------------------------------
// Hook's touch function
//--------------------------------------------------------------------
void() ChainTouch =
{
if (!(self.owner.hook & HOOK_ON))
{
DropHook();
return;
}
if (other.takedamage)
T_Damage (other, self, self.owner, 10 );
if (other.solid == SOLID_SLIDEBOX)
{
sound (self, CHAN_AUTO, "shambler/smack.wav", 1, ATTN_NORM);
SpawnBlood (self.origin, self.velocity, 10);
setorigin (self, other.origin + other.mins + other.size * 0.5);
}
else
{
sound (self, CHAN_AUTO, "player/axhit2.wav", 1, ATTN_NORM);
self.avelocity = '0 0 0';
}
self.velocity = other.velocity;
// Rob
if (! (self.owner.hook & HOOK_SG_STOP) )
self.owner.hook = self.owner.hook | SHRINK_ON;
self.enemy = other;
self.nextthink = time + 0.1;
self.think = HookBehavior;
self.touch = SUB_Null;
};
//--------------------------------------------------------------------
// Limit hook length during launch
//--------------------------------------------------------------------
void() LaunchHook =
{
local vector chainvec; // chain vector
local float chainlength; // length of extended chain
chainvec = self.origin - (self.owner.origin + '0 0 16');
chainlength = vlen (chainvec);
// armorvalue is used to hold current length of chain
self.armorvalue = chainlength;
// Rob; added death check
if (chainlength > MAX_CHAIN_LEN ||
self.owner.solid == SOLID_NOT)
{
DropHook();
return;
}
self.nextthink = time + 0.1;
};
//--------------------------------------------------------------------
// Initiates the hook
//--------------------------------------------------------------------
void(entity myself) InitiateHook =
{
local entity newhook;
newhook = spawn ();
newhook.owner = myself;
newhook.movetype = MOVETYPE_FLY;
newhook.solid = SOLID_BBOX;
setmodel (newhook, "progs/hook.mdl");
setsize (newhook, '0 0 0', '0 0 0');
makevectors (myself.v_angle);
setorigin (newhook, myself.origin + (v_forward*16) + '0 0 16' );
newhook.velocity = v_forward*1000;
newhook.angles = vectoangles(newhook.velocity);
newhook.avelocity = '0 0 600';
sound (myself, CHAN_AUTO, "weapons/ax1.wav", 1, ATTN_NORM);
newhook.goalentity = CreateChain (newhook, myself, 8);
newhook.touch = ChainTouch;
newhook.nextthink = time + 0.1 ;
newhook.think = LaunchHook;
};
//--------------------------------------------------------------------
// Checks impulse
//--------------------------------------------------------------------
void() CheckGrapHook =
{
if (self.impulse == I_HOOK)
{
if (!(self.hook & HOOK_OUT) )
{
// flags that one instance of hook is spawned
self.hook = self.hook | HOOK_OUT;
// flags last activated hook impulse as being ON
self.hook = self.hook | HOOK_ON;
InitiateHook (self);
return;
}
}
if (self.hook & HOOK_ON)
{
// release hook
if (self.impulse == I_HOOK)
{
self.hook = self.hook - (self.hook & HOOK_ON);
return;
}
// hop of chain and release hook
if ( (self.button2) &&
(!(self.flags & FL_ONGROUND)) &&
(self.flags & FL_JUMPRELEASED) &&
(!(self.flags & FL_INWATER)) )
{
self.hook = self.hook - (self.hook & HOOK_ON);
self.velocity_z = self.velocity_z + 200;
sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
return;
}
// deactivate chain growth or shrink
if (self.impulse == I_STOP)
{
self.hook = self.hook | HOOK_SG_STOP; // Rob
self.hook = self.hook - (self.hook & GROW_ON);
self.hook = self.hook - (self.hook & SHRINK_ON);
return;
}
// activate chain growth
if (self.impulse == I_GROW)
{
self.hook = self.hook | GROW_ON;
self.hook = self.hook - (self.hook & SHRINK_ON);
return;
}
// activate chain shrinking
if (self.impulse == I_SHRINK)
{
self.hook = self.hook | SHRINK_ON;
self.hook = self.hook - (self.hook & GROW_ON);
}
}
};